/**
 * 
 */
package cz.cuni.mff.abacs.burglar.logics.objects.positions;

import cz.cuni.mff.abacs.burglar.logics.DataMap;
import cz.cuni.mff.abacs.burglar.logics.objects.BaseInterface;
import cz.cuni.mff.abacs.burglar.logics.objects.BaseObject;
import cz.cuni.mff.abacs.burglar.logics.objects.Room;


/**
 * Connects rooms together.
 * 
 * @author abacs
 *
 */
public class Door extends BasePosition implements Lockable, Position {
	
	
	/**
	 * Changeable property. */
	protected boolean _isLocked = false;
	
	/**
	 * Changeable property. */
	protected boolean _isClosed = true;
	
	/**
	 * Not changeable property. 
	 * Default value is 0; */
	protected final int _keyId;
	
	/**
	 * Not changeable property. */
	protected final int _fromId;
	
	/**
	 * Not changeable property. */
	protected final int _toId;
	
	
	// -------------------------------------------------------------------------
	// constructors:
	
	
	/**
	 * 
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param fromRoom
	 * @param toRoom
	 * @param isClosed
	 * @param referenceMap
	 */
	public Door(
			int id,
			int x,
			int y,
			Room fromRoom,
			Room toRoom,
			boolean isClosed,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.DOOR, x, y, false, -1, referenceMap);
		this._fromId = fromRoom.getId();
		this._toId = toRoom.getId();
		this._isClosed = isClosed;
		this._isLocked = false;
		this._keyId = 0;
		
		this._node.walkable = true;
	}
	
	
	/**
	 * 
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param fromRoomId
	 * @param toRoomId
	 * @param isClosed
	 * @param referenceMap
	 */
	public Door(
			int id,
			int x,
			int y,
			int fromRoomId,
			int toRoomId,
			boolean isClosed,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.DOOR, x, y, false, -1, referenceMap);
		this._fromId = fromRoomId;
		this._toId = toRoomId;
		this._isClosed = isClosed;
		this._isLocked = false;
		this._keyId = 0;
		
		this._node.walkable = true;
	}
	
	
	/**
	 * 
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param fromRoom
	 * @param toRoom
	 * @param isClosed
	 * @param isLocked
	 * @param keyId
	 * @param referenceMap
	 */
	public Door(
			int id,
			int x,
			int y,
			Room fromRoom,
			Room toRoom,
			boolean isClosed,
			boolean isLocked,
			int keyId,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.DOOR, x, y, false, -1, referenceMap);
		this._fromId = fromRoom.getId();
		this._toId = toRoom.getId();
		this._isClosed = isClosed;
		this._isLocked = isLocked;
		this._keyId = keyId;
		
		if(this._isClosed == false)
			this._node.walkable = true;
		else
			this._node.walkable = false;
	}
	
	
	/**
	 * 
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param fromRoom
	 * @param toRoom
	 * @param isClosed
	 * @param isLocked
	 * @param keyId
	 * @param referenceMap
	 */
	public Door(
			int id,
			int x,
			int y,
			int fromRoomId,
			int toRoomId,
			boolean isClosed,
			boolean isLocked,
			int keyId,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.DOOR, x, y, false, -1, referenceMap);
		this._fromId = fromRoomId;
		this._toId = toRoomId;
		this._isClosed = isClosed;
		this._isLocked = isLocked;
		this._keyId = keyId;
		
		if(this._isClosed == false)
			this._node.walkable = true;
		else
			this._node.walkable = false;
	}
	
	
	protected Door(Door other, DataMap referenceMap) {
		super(other, referenceMap);
		
		this._fromId = other._fromId;
		this._toId = other._toId;
		this._isClosed = other._isClosed;
		this._isLocked = other._isLocked;
		this._keyId = other._keyId;
	}
	
	
	// -------------------------------------------------------------------------
	// Lockable:
	
	
	@Override
	public boolean open() {
		if(this._isLocked == false || this._isClosed == false){
			this._isClosed = false;
			return true;
		}
		return false;
	}
	
	
	@Override
	public boolean close() {
		this._isClosed = true;
		return true;
	}
	

	@Override
	public boolean unlock(int keyId) {
		if(this._isLocked == false)
			return true;
		if(this._keyId == keyId){
			this._isLocked = false;
			return true;
		}
		return false;
	}

	
	@Override
	public boolean lock(int keyId) {
		if(this._isClosed == false)
			return false;
		if(this._isLocked)
			return true;
		if(this._keyId == keyId){
			this._isLocked = true;
			return true;
		}
		return false;
	}
	
	
	@Override
	public int getKeyId() {
		return this._keyId;
	}
	
	
	@Override
	public boolean isClosed() {
		return this._isClosed;
	}

	
	@Override
	public boolean isLocked() {
		return this._isLocked;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * Returns the rooms that are connected to it.
	 */
	public Room[] getRooms() {
		return 
			new Room[]{
				this._referenceMap.getRoom(this._fromId),
				this._referenceMap.getRoom(this._toId)
			};
	}
	
	
	/**
	 * Returns the rooms that are connected to it.
	 */
	public int[] getRoomIds() {
		return 
			new int[]{
				this._fromId,
				this._toId};
	}
	
	@Override
	public boolean isInRoom(Room room) {
		if(this._fromId == room.getId() || this._toId == room.getId())
			return true;
		return false;
	}
	
	
	@Override
	public boolean isInRoom(int roomId) {
		if(this._fromId == roomId || this._toId == roomId)
			return true;
		return false;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	@Override
	public boolean isOperable() {
		return true;
	}
	
	
	@Override
	public boolean isTrap() {
		return false;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * From far the agent can see whether the door is opened.
	 * It can't see whether it's locked.
	 */
	@Override
	public Position examinedFromFar() {
		return new Door(
				this.getId(),
				this.getX(),
				this.getY(),
				this._fromId,
				this._toId,
				this._isClosed,
				null
		);
	}
	
	
	/**
	 * From near the agent can see whether the door is opened.
	 * It can see whether it's locked.
	 */
	@Override
	public Position examinedFromNear() {
		return new Door(
				this.getId(),
				this.getX(),
				this.getY(),
				this._fromId,
				this._toId,
				this._isClosed,
				this._isLocked,
				this._keyId,
				null
		);
	}
	
	
	@Override
	public boolean matchesFromFar(Position position) {
		if(super.matches(position) == false)
			return false;
		
		Door door = (Door) position;
		
		if(this._isClosed == door._isClosed){
			return true;
		}else{
			return false;
		}
	}
	
	
	@Override
	public boolean matchesFromClose(Position position) {
		if(super.matches(position) == false)
			return false;
		
		Door door = (Door) position;
		
		if(
			this._isClosed == door._isClosed &&
			this._isLocked == door._isLocked &&
			this.getKeyId() == door.getKeyId()
		){
			return true;
		}else{
			return false;
		}
	}
	
	
	@Override
	public void copyChangeables(Position original) {
		assert(original.isTypeOf(BaseInterface.Type.DOOR));
		Door original_ =  (Door)original;
		this._isLocked = original_._isLocked;
		this._isClosed = original_._isClosed;
	}
	
	
	@Override
	public Position copy(DataMap reference) {
		return new Door(this, reference);
	}
	
	
}
